@create $root_class named "generic message dispatch object",dispatch
@prop dispatch."messages_in" {} r
@prop dispatch."messages_out" {} r
;dispatch.("unique") = 0

@verb dispatch:"parse_send_args" this none this
@program dispatch:parse_send_args
"Usage:  :parse_send_args(msg, @posargs, @keywordargs)";
"";
"Transform a given message's arguments (mostly given positionally) into the correct form for MCP.  The cord type has an ordered list of argument keywords for all valid messages; these are matched with the arguments provided to produce an alist.  If more arguments are provided than keywords are available, then the remaining arguments should be {keyword, value} pairs.  This allows the passing of optional arguments and such.";
"";
"This verb returns an alist suitable for use with :client_notify().";
"";
"Examples:";
"  .messages_out = {{\"edit\", {\"name\", \"text\"}}}";
"  :parse_send_args(\"edit\", \"#123.foo\", {\"This is the first line.\"})";
"    => {{\"name\", \"#123.foo\"}, {\"text\", {\"This is the first line.\"}}}";
"  :parse_send_args(\"edit\", \"#123:foo\", {\"Hi!\"}, {\"type\", \"MOO-Code\"})";
"    => {{\"name\", \"#123.foo\"}, {\"text\", {\"Hi!\"}}, {\"type\", \"MOO-Code\"}}";
{msg, @rest} = args;
a = $list_utils:assoc(msg, this.messages_out);
if (!a)
  raise(E_INVARG, "Invalid message");
endif
keywords = a[2];
lkeywords = length(keywords);
lrest = length(rest);
if (lrest < lkeywords)
  raise(E_ARGS, "Incorrect number of message arguments");
endif
return {@$list_utils:make_alist({keywords, rest[1..lkeywords]}), @rest[lkeywords + 1..$]};
.

@verb dispatch:"parse_receive_args" this none this
@program dispatch:parse_receive_args
"Usage:  :parse_receive_args(msg, alist)";
"";
"Transform a messages arguments from an alist into a mostly-positional list.  The cord type has an ordered list of argument keywords for all valid messages; these are used to construct an ordered list of the items from the alist that correspond to those keywords.  If there are items in the alist that do not match a known keyword, they will be appended to the positional list with keywords attached.";
"";
"Examples:";
"  .messages_in = {{\"edit\", {\"name\", \"text\"}}}";
"  :parse_receive_args({{\"name\", \"#123.foo\"}, {\"text\", {\"Hi!\"}}})";
"    => {\"#123.foo\", \"Hi!\"}";
"  :parse_receive_args({{\"name\", \"#123.foo\"}, {\"text\", {\"Hi!\"}}, {\"type\", \"MOO-Code\"}})";
"    => {\"#123.foo\", \"Hi!\", {\"type\", \"MOO-Code\"}};";
{msg, alist} = args;
a = $list_utils:assoc(msg, this.messages_in);
if (!a)
  "this should be caught upstream.";
  raise(E_INVARG, "Invalid cord message");
endif
ret = {};
for keyword in (a[2])
  i = $list_utils:iassoc(keyword, alist);
  if (!i)
    "this too should be caught.";
    raise(E_INVARG, "Missing argument in cord message");
  endif
  ret = {@ret, alist[i][2]};
  alist = listdelete(alist, i);
endfor
return {@ret, @alist};
.

@verb dispatch:"set_messages_in set_messages_out" this none this
@program dispatch:set_messages_in
"This is the standard :set_foo verb.  It allows the property to be set if called by this or called with adequate permissions (this's owner or wizardly).";
if ((caller == this) || $perm_utils:controls(caller_perms(), this))
  return this.(verb[5..length(verb)]) = args[1];
else
  return E_PERM;
endif
.

"***finished***

